<template>
	<view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']"
		:style="[{ zIndex: zIndex }]" @touchmove.stop.prevent="clear">
		<view @touchstart="touchstart">
			<uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" :duration="duration"
				:show="showTrans" @click="onTap" />
			<uni-transition key="2" :mode-class="ani" name="content" :styles="{ ...transClass, ...borderRadius }"
				:duration="duration" :show="showTrans" @click="onTap">
				<view v-if="showPopup" class="uni-popup__wrapper" :style="[{ backgroundColor: bg }, borderRadius]"
					:class="[popupstyle]" @click="clear">
					<uni-icons v-if="showClose" class="close-icon" color="#F6F6F6" type="closeempty" size="32"
						@click="close"></uni-icons>
					<slot />
				</view>
			</uni-transition>
		</view>
		<!-- #ifdef H5 -->
		<keypress v-if="maskShow" @esc="onTap" />
		<!-- #endif -->
	</view>
	<!-- #ifdef MP -->
	<view v-else style="display: none">
		<slot></slot>
	</view>
	<!-- #endif -->
</template>

<script>
	// #ifdef H5
	import keypress from './keypress.js';
	// #endif

	/**
	 * PopUp 弹出层
	 * @description 弹出层组件，为了解决遮罩弹层的问题
	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
	 * @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
	 * 	@value top 顶部弹出
	 * 	@value center 中间弹出
	 * 	@value bottom 底部弹出
	 * 	@value left		左侧弹出
	 * 	@value right  右侧弹出
	 * 	@value message 消息提示
	 * 	@value dialog 对话框
	 * 	@value share 底部分享示例
	 * @property {Boolean} animation = [true|false] 是否开启动画
	 * @property {Boolean} maskClick = [true|false] 蒙版点击是否关闭弹窗(废弃)
	 * @property {Boolean} isMaskClick = [true|false] 蒙版点击是否关闭弹窗
	 * @property {String}  backgroundColor 主窗口背景色
	 * @property {String}  maskBackgroundColor 蒙版颜色
	 * @property {Boolean} safeArea		   是否适配底部安全区
	 * @event {Function} change 打开关闭弹窗触发，e={show: false}
	 * @event {Function} maskClick 点击遮罩触发
	 */
	import sheep from '@/sheep';

	export default {
		name: 'SuPopup',
		components: {
			// #ifdef H5
			keypress,
			// #endif
		},
		emits: ['change', 'maskClick', 'close'],
		props: {
			// 开启状态
			show: {
				type: Boolean,
				default: false,
			},
			// 顶部，底部时有效
			space: {
				type: Number,
				default: 0,
			},
			// 默认圆角
			round: {
				type: [String, Number],
				default: 0,
			},
			// 是否显示关闭
			showClose: {
				type: Boolean,
				default: false,
			},
			// 开启动画
			animation: {
				type: Boolean,
				default: true,
			},
			// 弹出层类型，可选值，top: 顶部弹出层；bottom：底部弹出层；center：全屏弹出层
			// message: 消息提示 ; dialog : 对话框
			type: {
				type: String,
				default: 'bottom',
			},
			// maskClick
			isMaskClick: {
				type: Boolean,
				default: null,
			},
			// TODO 2 个版本后废弃属性 ，使用 isMaskClick
			maskClick: {
				type: Boolean,
				default: null,
			},
			// 可设置none
			backgroundColor: {
				type: String,
				default: '#F8F3E7',
			},
			backgroundImage: {
				type: String,
				default: '',
			},
			safeArea: {
				type: Boolean,
				default: true,
			},
			maskBackgroundColor: {
				type: String,
				default: 'rgba(0, 0, 0, 0.4)',
			},
			zIndex: {
				type: [String, Number],
				default: 10075,
			},
		},

		watch: {
			show: {
				handler: function(newValue, oldValue) {
					if (typeof oldValue === 'undefined' && !newValue) {
						return;
					}
					if (newValue) {
						this.open();
					} else {
						this.close();
					}
				},
				immediate: true,
			},
			/**
			 * 监听type类型
			 */
			type: {
				handler: function(type) {
					if (!this.config[type]) return;
					this[this.config[type]](true);
				},
				immediate: true,
			},
			isDesktop: {
				handler: function(newVal) {
					if (!this.config[newVal]) return;
					this[this.config[this.type]](true);
				},
				immediate: true,
			},
			/**
			 * 监听遮罩是否可点击
			 * @param {Object} val
			 */
			maskClick: {
				handler: function(val) {
					this.mkclick = val;
				},
				immediate: true,
			},
			isMaskClick: {
				handler: function(val) {
					this.mkclick = val;
				},
				immediate: true,
			},
			// H5 下禁止底部滚动
			showPopup(show) {
				// #ifdef H5
				// fix by mehaotian 处理 h5 滚动穿透的问题
				document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible';
				// #endif
			},
		},
		data() {
			return {
				sheep,
				duration: 300,
				ani: [],
				showPopup: false,
				showTrans: false,
				popupWidth: 0,
				popupHeight: 0,
				config: {
					top: 'top',
					bottom: 'bottom',
					center: 'center',
					left: 'left',
					right: 'right',
					message: 'top',
					dialog: 'center',
					share: 'bottom',
				},
				maskClass: {
					position: 'fixed',
					bottom: 0,
					top: 0,
					left: 0,
					right: 0,
					backgroundColor: 'rgba(0, 0, 0, 0.4)',
				},
				transClass: {
					position: 'fixed',
					left: 0,
					right: 0,
				},
				maskShow: true,
				mkclick: true,
				popupstyle: this.isDesktop ? 'fixforpc-top' : 'top',
			};
		},
		computed: {
			isDesktop() {
				return this.popupWidth >= 500 && this.popupHeight >= 500;
			},
			bg() {
				if (this.backgroundColor === '' || this.backgroundColor === 'none') {
					return 'transparent';
				}
				return this.backgroundColor;
			},
			borderRadius() {
				if (this.round) {
					if (this.type === 'bottom') {
						return {
							'border-top-left-radius': parseFloat(this.round) + 'px',
							'border-top-right-radius': parseFloat(this.round) + 'px',
						};
					}
					if (this.type === 'center') {
						return {
							'border-top-left-radius': parseFloat(this.round) + 'px',
							'border-top-right-radius': parseFloat(this.round) + 'px',
							'border-bottom-left-radius': parseFloat(this.round) + 'px',
							'border-bottom-right-radius': parseFloat(this.round) + 'px',
						};
					}
					if (this.type === 'top') {
						return {
							'border-bottom-left-radius': parseFloat(this.round) + 'px',
							'border-bottom-right-radius': parseFloat(this.round) + 'px',
						};
					}
				}
			},
		},
		mounted() {
			const fixSize = () => {
				const {
					windowWidth,
					windowHeight,
					windowTop,
					safeArea,
					screenHeight,
					safeAreaInsets
				} =
				sheep.$platform.device;
				this.popupWidth = windowWidth;
				this.popupHeight = windowHeight + (windowTop || 0);
				// TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异，需要框架修复
				if (safeArea && this.safeArea) {
					// #ifdef MP-WEIXIN
					this.safeAreaInsets = screenHeight - safeArea.bottom;
					// #endif
					// #ifndef MP-WEIXIN
					this.safeAreaInsets = safeAreaInsets.bottom;
					// #endif
				} else {
					this.safeAreaInsets = 0;
				}
			};
			fixSize();
			// #ifdef H5
			// window.addEventListener('resize', fixSize)
			// this.$once('hook:beforeDestroy', () => {
			// 	window.removeEventListener('resize', fixSize)
			// })
			// #endif
		},
		// #ifndef VUE3
		// TODO vue2
		destroyed() {
			this.setH5Visible();
		},
		// #endif
		// #ifdef VUE3
		// TODO vue3
		unmounted() {
			this.setH5Visible();
		},
		// #endif
		created() {
			// this.mkclick =  this.isMaskClick || this.maskClick
			if (this.isMaskClick === null && this.maskClick === null) {
				this.mkclick = true;
			} else {
				this.mkclick = this.isMaskClick !== null ? this.isMaskClick : this.maskClick;
			}
			if (this.animation) {
				this.duration = 300;
			} else {
				this.duration = 0;
			}
			// TODO 处理 message 组件生命周期异常的问题
			this.messageChild = null;
			// TODO 解决头条冒泡的问题
			this.clearPropagation = false;
			this.maskClass.backgroundColor = this.maskBackgroundColor;
		},
		methods: {
			setH5Visible() {
				// #ifdef H5
				// fix by mehaotian 处理 h5 滚动穿透的问题
				document.getElementsByTagName('body')[0].style.overflow = 'visible';
				// #endif
			},
			/**
			 * 公用方法，不显示遮罩层
			 */
			closeMask() {
				this.maskShow = false;
			},
			/**
			 * 公用方法，遮罩层禁止点击
			 */
			disableMask() {
				this.mkclick = false;
			},
			// TODO nvue 取消冒泡
			clear(e) {
				// #ifndef APP-NVUE
				e.stopPropagation();
				// #endif
				this.clearPropagation = true;
			},

			open(direction) {
				// fix by mehaotian 处理快速打开关闭的情况
				if (this.showPopup) {
					clearTimeout(this.timer);
					this.showPopup = false;
				}
				let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share'];
				if (!(direction && innerType.indexOf(direction) !== -1)) {
					direction = this.type;
				}
				if (!this.config[direction]) {
					console.error('缺少类型：', direction);
					return;
				}
				this[this.config[direction]]();
				this.$emit('change', {
					show: true,
					type: direction,
				});
			},
			close(type) {
				this.showTrans = false;
				this.$emit('change', {
					show: false,
					type: this.type,
				});
				this.$emit('close');
				clearTimeout(this.timer);
				// // 自定义关闭事件
				// this.customOpen && this.customClose()
				this.timer = setTimeout(() => {
					this.showPopup = false;
				}, 300);
			},
			// TODO 处理冒泡事件，头条的冒泡事件有问题 ，先这样兼容
			touchstart() {
				this.clearPropagation = false;
			},

			onTap() {
				if (this.clearPropagation) {
					// fix by mehaotian 兼容 nvue
					this.clearPropagation = false;
					return;
				}
				this.$emit('maskClick');
				if (!this.mkclick) return;
				this.close();
			},
			/**
			 * 顶部弹出样式处理
			 */
			top(type) {
				this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top';
				this.ani = ['slide-top'];
				this.transClass = {
					position: 'fixed',
					left: 0,
					right: 0,
					top: this.space + 'px',
					backgroundColor: this.bg,
				};
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return;
				this.showPopup = true;
				this.showTrans = true;
				this.$nextTick(() => {
					if (this.messageChild && this.type === 'message') {
						this.messageChild.timerClose();
					}
				});
			},
			/**
			 * 底部弹出样式处理
			 */
			bottom(type) {
				this.popupstyle = 'bottom';
				this.ani = ['slide-bottom'];
				this.transClass = {
					position: 'fixed',
					left: 0,
					right: 0,
					bottom: 0,
					paddingBottom: this.safeAreaInsets + this.space + 'px',
					backgroundColor: this.bg,
				};
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return;
				this.showPopup = true;
				this.showTrans = true;
			},
			/**
			 * 中间弹出样式处理
			 */
			center(type) {
				this.popupstyle = 'center';
				this.ani = ['zoom-out', 'fade'];
				this.transClass = {
					position: 'fixed',
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column',
					/* #endif */
					bottom: 0,
					left: 0,
					right: 0,
					top: 0,
					justifyContent: 'center',
					alignItems: 'center',
				};
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return;
				this.showPopup = true;
				this.showTrans = true;
			},
			left(type) {
				this.popupstyle = 'left';
				this.ani = ['slide-left'];
				this.transClass = {
					position: 'fixed',
					left: 0,
					bottom: 0,
					top: 0,
					backgroundColor: this.bg,
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column',
					/* #endif */
				};
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return;
				this.showPopup = true;
				this.showTrans = true;
			},
			right(type) {
				this.popupstyle = 'right';
				this.ani = ['slide-right'];
				this.transClass = {
					position: 'fixed',
					bottom: 0,
					right: 0,
					top: 0,
					backgroundColor: this.bg,
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column',
					/* #endif */
				};
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return;
				this.showPopup = true;
				this.showTrans = true;
			},
		},
	};
</script>
<style lang="scss">
	// 关闭icon
	.close-icon {
		position: absolute;
		left: 50%;
		transform: translateX(-50%);
		bottom: -80rpx;
		z-index: 100;
	}

	.uni-popup {
		position: fixed;
		/* #ifndef APP-NVUE */
		z-index: 99;

		/* #endif */
		&.top,
		&.left,
		&.right {
			/* #ifdef H5 */
			top: var(--window-top);
			/* #endif */
			/* #ifndef H5 */
			top: 0;
			/* #endif */
		}

		.uni-popup__wrapper {
			/* #ifndef APP-NVUE */
			display: block;
			/* #endif */
			position: relative;
			background: v-bind(backgroundImage) no-repeat;
			background-size: 100% 100%;

			/* iphonex 等安全区设置，底部安全区适配 */
			/* #ifndef APP-NVUE */
			// padding-bottom: constant(safe-area-inset-bottom);
			// padding-bottom: env(safe-area-inset-bottom);
			/* #endif */
			&.left,
			&.right {
				/* #ifdef H5 */
				padding-top: var(--window-top);
				/* #endif */
				/* #ifndef H5 */
				padding-top: 0;
				/* #endif */
				flex: 1;
			}
		}
	}

	.fixforpc-z-index {
		/* #ifndef APP-NVUE */
		z-index: 999;
		/* #endif */
	}

	.fixforpc-top {
		top: 0;
	}
</style>